<template>
  <div class="base-search">
    <a-form
      class="search-form"
      ref="formRef"
      :layout="layout"
      :model="formResult"
      v-bind="$attrs"
      @finish="onFinish">

      <a-row :gutter="32">
        <a-col
          v-for="(item) in configJsonArrs"
          :key="item.name"
          :span="renderSpan(item.grow)">
          <slot :name="item.name">
            <a-form-item
              :label="item.label"
              v-bind="item">
              <component
                :is="item.component"
                :id="`form_item_${item.name}`"
                :_key="item.name"
                v-model:value="formResult[item.name]"
                v-bind="item.props"
                v-on="item.events || {}"
                @change="(evt) => watchItem(evt, item.watchMethod, item)"
                @focus="item.focus ? item.focus() : ''" >
                <!-- 插槽透传 -->
                <template 
                  v-for="(_, key) in _$slots" 
                  :key="key" 
                  v-slot:[key]="_">
                  <slot :name="key"></slot>
                </template>
              </component>
            </a-form-item>
          </slot>
        </a-col>
        <a-form-item class="form-item" v-if="footerItem">
          <slot name="footer">
            <a-button class="margin-right16" type="primary" html-type="submit"
              >查询</a-button
            >
            <a-button @click="onReset(true)">重置</a-button>
          </slot>
        </a-form-item>
      </a-row>
    </a-form>
  </div>
</template>

<script setup>
import {
  ref,
  reactive,
  defineProps,
  defineEmits,
  defineAsyncComponent,
  onMounted,
  computed,
  watch,
  useSlots
} from 'vue'

const props = defineProps({
  layout: {
    type: String,
    default: 'inline'
  },
  grid: {
    type: Number,
    validator(value) {
      return value >= 1 && value % 1 === 0
    },
    default: 1
  },
  footerItem: {
    type: Boolean,
    default: false
  },
  baseData: {
    type: Object,
    default: () => {}
  },
  configJsonArr: {
    type: Array,
    required: true,
    default: () => []
  }
})
const _$emit = defineEmits(['confirm', 'reset', 'watchItem'])
const _$slots = useSlots()

const span = ref(24)
const formRef = ref(null)
const formResult = reactive({})

/**
 * Mounted生命周期
 * 初始化默认值
 */
onMounted(() => {
  let { baseData, configJsonArr } = props

  if (baseData) {
    configJsonArr.map((item) => {
      formResult[item.name] = baseData[item.name] || undefined
    })
  }
})

/**
 * watch 监听 BaseData
 * deep: true
 */
watch(
  () => props.baseData,
  (value) => {
    Object.keys(value).map((key) => {
      formResult[key] = value[key]
    })
  },
  {
    deep: true
  }
)

/**
 * 初始化表单配置 Computed
 */
const configJsonArrs = computed(() => {
  let { grid, configJsonArr } = props

  const formComponents = configJsonArr.map((item) => {
    let { grow, type } = item
    if (grow === undefined) {
      grow = 1
    }

    if (grow && grow > grid) {
      grow = grid
    }

    return {
      ...item,
      grow,
      component: defineAsyncComponent(() => import(`./${type}`))
    }
  })

  return formComponents
})

const renderSpan = (grow) => {
  let { grid, layout } = props

  if(layout === 'inline') {
    return -1
  }

  return (span.value / grid) * grow
}

/** 过滤结果 */
const returnSubmitResult = (values) => {
  // 过滤空值
  const filteredValues = Object.entries(values).filter(([key, value]) => {
    return value !== '' && value !== undefined && value !== null
  })

  // 过滤空数组
  const notEmptyArrays = filteredValues.filter(([key, value]) => {
    return !Array.isArray(value) || value.length > 0
  })

  const result = notEmptyArrays.reduce((acc, [key, value]) => {
    acc[key] = value
    return acc
  }, {})

  return result
}

/**
 * 表单确认事件 onFinish
 */
const onFinish = (values) => {
  _$emit('confirm', returnSubmitResult(values))
}

/**重置表单事件  */
const onReset = (status = false) => {
  formRef.value.resetFields()

  if (status) {
    _$emit('reset')
  }
}

/** 外部提交表单方法  */
const onSubmit = async () => {
  try {
    const values = await formRef.value.validateFields()

    return returnSubmitResult(values)
  } catch (error) {
    console.error(`submit error: ${error}`)
  }
}

/** 监听字段变化 */
const watchItem = (evt, watchMethod, item) => {
  let value = undefined
  if (evt) {
    value = evt.target ? evt.target.value : evt
  }

  if (item.watch) {
    _$emit('watchItem', {
      method: watchMethod,
      key: item.key,
      value
    })
  }
}

/** 设置表单字段 */
const setOnlyFieldsValue = (key, value) => {
  formResult[key] = value
}

/** 暴露外部使用方法 */
defineExpose({
  setOnlyFieldsValue,
  onSubmit,
  onReset
})
</script>

<style scoped lang="less">
.base-search {

  .ant-row{
    margin-left: 0 !important;
  }
  .ant-form-inline {
    .ant-form-item .ant-select {
      min-width: 199px;
    }
  }
  .ant-form-horizontal {
    .ant-form-item {
      margin-bottom: 0 !important;
    }
  }
  .ant-form-vertical {
    .ant-form-item {
      // width: 100%;
    }
  }

  /deep/ .ant-form-item {
    min-height: 50px;
    padding-top: 6px;
    .ant-form-item-label {
      min-width: 80px;
    }
  }

  /deep/ .custom-item {
    margin-bottom: 0;
    label {
      width: 100%;
    }
    .ant-select {
      text-align: left;
    }
  }
}
.base-search.flex-item {
  /deep/ .ant-form-horizontal .ant-picker {
    width: 100%;
  }
}
</style>
